package org.lestr.secuel.sogl;

import java.awt.Component;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.util.Iterator;

import java.util.logging.Level;
import java.util.logging.Logger;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;

import org.lestr.secuel.m3ds.Affichage;
import org.lestr.secuel.m3ds.Camera;
import org.lestr.secuel.m3ds.Univers;
import org.lestr.secuel.m3ds.lumieres.Lumiere;
import org.lestr.secuel.m3ds.lumieres.Spot;
import org.lestr.secuel.m3ds.maths.IPoint2d;
import org.lestr.secuel.m3ds.maths.IVecteur3d;
import org.lestr.secuel.m3ds.objets2D.IImage;
import org.lestr.secuel.m3ds.objets3D.Materiau;
import org.lestr.secuel.m3ds.objets3D.IObjet3d;
import org.lestr.secuel.m3ds.objets3D.ITriangle;
import org.lestr.secuel.sogl.lumieres.SOGLAmpoule;
import org.lestr.secuel.sogl.lumieres.SOGLLumiere;
import org.lestr.secuel.sogl.lumieres.SOGLLumiereAmbiante;
import org.lestr.secuel.sogl.lumieres.SOGLSpot;
import org.lestr.secuel.sogl.maths.Transformation3D;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.texture.TextureData;
import com.sun.opengl.util.texture.TextureIO;

public class SOGLAffichage implements Affichage, GLEventListener {


    // Variables statiques
    private static SOGLAffichage singleton;


    /** Initialisation statique */
    static {

        File rep = new File(System.getProperty("java.library.path").split(";")[0]);

        try {

            copierLibrairie(rep.getAbsolutePath(), "gluegen-rt.dll");

        } catch (Exception ex) {
            Logger.getLogger(SOGLAffichage.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {

            copierLibrairie(rep.getAbsolutePath(), "libgluegen-rt.so");

        } catch (Exception ex) {
            Logger.getLogger(SOGLAffichage.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {

            copierLibrairie(rep.getAbsolutePath(), "jogl_awt.dll");
            copierLibrairie(rep.getAbsolutePath(), "jogl_cg.dll");
            copierLibrairie(rep.getAbsolutePath(), "jogl.dll");

        } catch (Exception ex) {
            Logger.getLogger(SOGLAffichage.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {

            copierLibrairie(rep.getAbsolutePath(), "libjogl_awt.so");
            copierLibrairie(rep.getAbsolutePath(), "libjogl_cg.so");
            copierLibrairie(rep.getAbsolutePath(), "libjogl.so");

        } catch (Exception ex) {
            Logger.getLogger(SOGLAffichage.class.getName()).log(Level.SEVERE, null, ex);
        }

    }// FIN Initialisation statique


    /** Copie une librairie native présente dans les ressources dans un répertoire. */
    private static void copierLibrairie(String rep,
                                        String nom) {

        try {

            // Variables locales
            int nbLus;
            byte[] données = new byte[1024 * 128];
            InputStream entrée;
            OutputStream sortie;
            File lib;

            // Récupère le fichier à crée de la librairie
            lib = new File(rep + "/" + nom);

            // S'il existe le supprime
            if (lib.exists())
                lib.delete();

            // Le crée
            lib.createNewFile();

            // Ouvre l'original en lecture
            entrée = SOGLAffichage.class.getClassLoader().getResourceAsStream(nom);

            // Ouvre la copie en écriture
            sortie = new FileOutputStream(lib);

            // Recopie les données
            nbLus = 0;
            while ((nbLus = entrée.read(données)) != -1) {
                sortie.write(données, 0, nbLus);
                sortie.flush();
            }

            // Ferme l'original et la copie
            sortie.close();
            entrée.close();

            // le rend lisible et exécutable
            lib.setExecutable(true, false);
            lib.setReadable(true, false);

        } catch (Exception e) {
        }

    }// FIN copierLibrairie


    /** retourne le singleton de l'affichage */
    public static synchronized SOGLAffichage retSingleton() {

        // Initialise si besoin
        if (singleton == null)
            singleton = new SOGLAffichage();

        // Retourne le singleton
        return singleton;

    }// FIN retSingleton


    // Déclaration des attributs
    private GLCanvas canevas;


    private SOGLUnivers univers;


    private GL gl;


    private GLU glu;


    private int largeur;


    private int hauteur;


    private Camera caméra;


    private Materiau materiauCourant;


    private Iterator<IPoint2d> coordonnées;


    private int textureID;


    private float transparence;


    private boolean drapeauActualiser;


    private boolean drapeauUnivers;


    /** Constructeur */
    private SOGLAffichage() {

        // Instanciation des attributs
        canevas = new GLCanvas();
        univers = null;
        gl = canevas.getGL();
        glu = new GLU();
        largeur = 0;
        hauteur = 0;
        caméra = null;
        materiauCourant = null;
        coordonnées = null;
        textureID = 0;
        transparence = 0;
        drapeauActualiser = false;
        drapeauUnivers = false;

        // Pose d'écouteurs
        canevas.addGLEventListener(this);

        // Lance le rafraichissement continuel de l'affichage
        Animator anim = new Animator(canevas);
        anim.start();

    }// FIN Constructeur


    /** Défini l'univers à afficher */
    public void setUnivers(Univers univers) {

        // S'il y a une caméra dans l'univers la donne à l'affichage
        if (univers.getCaméras().iterator().hasNext())
            setCaméra(univers.getCaméras().iterator().next());
        // Sinon en construit une et la donne à l'affichage
        else {
            univers.ajoutCaméra(Usine.getSingleton().caméra());
            setCaméra(univers.getCaméras().iterator().next());
        }

        // Si un univers différent est déjà défini
        if (this.univers != null && univers != null && this.univers != univers) {

            // Change l'univers
            this.univers = (SOGLUnivers) univers;

            // Libère la mémoire
            System.gc();

        } // Sinon le change directement
        else {
            this.univers = (SOGLUnivers) univers;
            synchronized (this) {
                notifyAll();
            }
        }

    }// FIN defUnivers


    /** Retourne l'univers affiché */
    public Univers getUnivers() {

        return univers;

    }// FIN retUnivers


    /** Défini la résolution d'affichage */
    public void setRésolution(int largeur,
                              int hauteur) {

        // Mémorise
        this.largeur = largeur;
        this.hauteur = hauteur;

        // Applique
        gl.glViewport(0, 0, largeur, hauteur);

    }// FIN defRésolution


    /** Retourne la largeur de la résolution */
    public int getLargeur() {

        return largeur;

    }// FIN retLargeur


    /** Retourne la hauteur de résolution */
    public int getHauteur() {

        return hauteur;

    }// FIN retHauteur


    /** Défini le nombre de couleurs en bits */
    public void getNbCouleurs(int nbCouleurs) {
    }// FIN defNbCouleurs


    /** Retourne le nombre de couleurs en bits */
    public int getNbCouleurs() {
        return 0;
    }// FIN retNbCouleurs


    /** Retourne la caméra de l'affichage */
    public Camera getCaméra() {

        return caméra;

    }// FIN getCaméra


    @Override
    public void setCaméra(Camera caméra) {

        this.caméra = caméra;

    }// FIN setCaméra


    /** Actualise l'affichage */
    public void actualiser() {

        // Contrôle qu'un univers soit définit
        try {
            synchronized (this) {
                while (univers == null)
                    wait();
            }
        } catch (InterruptedException e) {
        }

        // Autorisation de rafraichir
        synchronized (this) {
            drapeauActualiser = true;
            notifyAll();
        }

        // Attend la fin du rafraichissement
        try {
            synchronized (this) {
                while (drapeauActualiser)
                    wait();
            }
        } catch (InterruptedException e) {
        }

    }// FIN actualiser


    /** Actualise les lumières */
    private void actualiserLumières() {

        // Parcours les lumières
        for (Lumiere lumière : univers.getLumières()) {

            // Initialisation
            gl.glLoadIdentity();

            // Si lumière ambiante
            if (lumière instanceof SOGLLumiereAmbiante) {

                // Couleur et intensité
                float[] couleur = new float[]{(float) lumière.getRouge() / 255,
                                              (float) lumière.getVert() / 255,
                                              (float) lumière.getBleu() / 255,
                                              (float) lumière.getIntensité() / 100};
                gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, couleur, 0);

            }

            // Si ampoule
            if (lumière instanceof SOGLAmpoule) {

                // Couleur et intensité
                float[] couleur = new float[]{(float) lumière.getRouge() / 255,
                                              (float) lumière.getVert() / 255,
                                              (float) lumière.getBleu() / 255,
                                              (float) lumière.getIntensité() / 100};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_DIFFUSE, couleur, 0);
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_SPECULAR, couleur, 0);
                couleur = new float[]{0f, 0f, 0f, 1f};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_AMBIENT, couleur, 0);

                // Position
                float[] position = new float[]{(float) lumière.getX(), (float) lumière.getY(), (float) lumière.getZ()};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_POSITION, position, 0);

                // Angle
                gl.glLightf(((SOGLLumiere) lumière).getId(), GL.GL_SPOT_CUTOFF, 180.0f);

            }

            // Si spot
            if (lumière instanceof SOGLSpot) {

                // Angle
                gl.glLightf(((SOGLLumiere) lumière).getId(), GL.GL_SPOT_CUTOFF, (float) ((Spot) lumière).getAngle());

                // Couleur et intensité
                float[] couleur = new float[]{(float) lumière.getRouge() / 255,
                                              (float) lumière.getVert() / 255,
                                              (float) lumière.getBleu() / 255,
                                              (float) lumière.getIntensité() / 100};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_DIFFUSE, couleur, 0);
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_SPECULAR, couleur, 0);
                couleur = new float[]{0f, 0f, 0f, 1f};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_AMBIENT, couleur, 0);

                // Position
                float[] position = new float[]{(float) lumière.getX(), (float) lumière.getY(), (float) lumière.getZ()};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_POSITION, position, 0);

                // Direction
                Transformation3D transformation = new Transformation3D();
                IVecteur3d vecteurDirection = Usine.getSingleton().vecteur3D(1, 1, 1);
                transformation.setRotation(Usine.getSingleton().vecteur3D(1, 0, 0), Math.toRadians(((SOGLSpot) lumière).getAngleX()));
                transformation.transform(vecteurDirection);
                transformation.setRotation(Usine.getSingleton().vecteur3D(0, 1, 0), Math.toRadians(((SOGLSpot) lumière).getAngleY()));
                transformation.transform(vecteurDirection);
                transformation.setRotation(Usine.getSingleton().vecteur3D(0, 0, 1), Math.toRadians(((SOGLSpot) lumière).getAngleZ()));
                transformation.transform(vecteurDirection);
                float[] direction = new float[]{(float) vecteurDirection.obtenirX(),
                                                (float) vecteurDirection.obtenirY(),
                                                (float) vecteurDirection.obtenirZ()};
                gl.glLightfv(((SOGLLumiere) lumière).getId(), GL.GL_SPOT_DIRECTION, direction, 0);

                // Angle et atténuation angluaire
                gl.glLightf(((SOGLLumiere) lumière).getId(), GL.GL_SPOT_CUTOFF, 0.5f * (float) ((SOGLSpot) lumière).getAngle());
                gl.glLightf(((SOGLLumiere) lumière).getId(), GL.GL_SPOT_EXPONENT, 0.5f);

                // Atténuation
				/*glLightf(gl_index, GL_CONSTANT_ATTENUATION, lt->getAttenuationConstant());
                glLightf(gl_index, GL_LINEAR_ATTENUATION, lt->getAttenuationLinear());
                glLightf(gl_index, GL_QUADRATIC_ATTENUATION, lt->getAttenuationQuadric());*/

            }

        }

    }// FIN actualiserLumières


    /** Actualise les objets 3D */
    private void actualiserObjets3D() {

        // Parcours les objets
        for (IObjet3d objet : univers.getObjets3D()) {

            // Initialisation
            gl.glLoadIdentity();

            // Position
            gl.glTranslated(objet.obtenirPosition().obtenirX(),
                            objet.obtenirPosition().obtenirY(), 
                            objet.obtenirPosition().obtenirZ());

            // Rotation
            gl.glRotated(objet.obtenirOrientation().obtenirX(), 1, 0, 0);
            gl.glRotated(objet.obtenirOrientation().obtenirY(), 0, 1, 0);
            gl.glRotated(objet.obtenirOrientation().obtenirZ(), 0, 0, 1);

            // Dimension
            gl.glScaled(objet.obtenirDimension().obtenirX(), 
                        objet.obtenirDimension().obtenirY(), 
                        objet.obtenirDimension().obtenirZ());

            // Transparence
            transparence = objet.obtenirTransparence() / 100;
            if (transparence > 0) {
                gl.glEnable(GL.GL_BLEND);
                gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA);
            } else
                gl.glDisable(GL.GL_BLEND);

            // Mise en place du matériau par défaut
            mettreEnPlaceMatériau(objet.obtenirApparence().obtenirMatériauStandard());

            // Si on doit texturer à l'aide de coordonnées de texture
            coordonnées = null;
            if (!objet.obtenirApparence().estTexturageAutomatique()) {

                // Récupère les coordonnées de texture
                coordonnées = objet.obtenirApparence().obtenirCoordonnées().iterator();

                // Désactive l'auto-texturage
                gl.glDisable(GL.GL_TEXTURE_GEN_S);
                gl.glDisable(GL.GL_TEXTURE_GEN_T);

            } // Si on doit texturer de manière automatique
            else {

                // Sélectionne le numéro généré
                gl.glBindTexture(GL.GL_TEXTURE_2D, textureID);

                // Paramètre la génération
                gl.glTexGeni(GL.GL_S, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
                gl.glEnable(GL.GL_TEXTURE_GEN_S);
                gl.glTexGeni(GL.GL_T, GL.GL_TEXTURE_GEN_MODE, GL.GL_EYE_LINEAR);
                gl.glEnable(GL.GL_TEXTURE_GEN_T);

                double[] ps = new double[]{1, 0, 0, 0};
                double[] pt = new double[]{0, 1, 0, 0};
                DoubleBuffer psTampon = DoubleBuffer.wrap(ps);
                DoubleBuffer ptTampon = DoubleBuffer.wrap(pt);
                gl.glTexGendv(GL.GL_S, GL.GL_EYE_PLANE, psTampon);
                gl.glTexGendv(GL.GL_T, GL.GL_EYE_PLANE, ptTampon);

            }

            // On va dessiner des triangles
            gl.glBegin(GL.GL_TRIANGLES);

            // Parcours les triangles de l'objet courant
            for (ITriangle triangle : objet.obtenirTriangles()) {

                // Si matériau spécial, le met en place
                if (objet.obtenirApparence().obtenirMatériau(triangle) != null && objet.obtenirApparence().obtenirMatériau(triangle) != materiauCourant)
                    mettreEnPlaceMatériau(objet.obtenirApparence().obtenirMatériau(triangle));
                else if (materiauCourant != objet.obtenirApparence().obtenirMatériauStandard())
                    mettreEnPlaceMatériau(objet.obtenirApparence().obtenirMatériauStandard());

                // Met en place les coordonnées de texture
                if (coordonnées != null) {
                    IPoint2d point2D = coordonnées.next();
                    gl.glTexCoord2d(point2D.obtenirX(), point2D.obtenirY());
                }

                // Sommet 1 du triangle courant
                gl.glVertex3d(triangle.obtenirSommet1().obtenirX(),
                              triangle.obtenirSommet1().obtenirY(),
                              triangle.obtenirSommet1().obtenirZ());

                // Met en place les coordonnées de texture
                if (coordonnées != null) {
                    IPoint2d point2D = coordonnées.next();
                    gl.glTexCoord2d(point2D.obtenirX(), point2D.obtenirY());
                }

                // Sommet 2 du triangle courant
                gl.glVertex3d(triangle.obtenirSommet2().obtenirX(),
                              triangle.obtenirSommet2().obtenirY(),
                              triangle.obtenirSommet2().obtenirZ());

                // Met en place les coordonnées de texture
                if (coordonnées != null) {
                    IPoint2d point2D = coordonnées.next();
                    gl.glTexCoord2d(point2D.obtenirX(), point2D.obtenirY());
                }

                // Sommet 3 du triangle courant
                gl.glVertex3d(triangle.obtenirSommet3().obtenirX(),
                              triangle.obtenirSommet3().obtenirY(),
                              triangle.obtenirSommet3().obtenirZ());

            }

            // On a fini de dessiner les triangles
            gl.glEnd();

        }

    }// FIN actualiserObjets3D


    /** Met en place un matériau */
    private void mettreEnPlaceMatériau(Materiau matériau) {

        // Variables locales
        float[] couleur;

        // Réaction à la lumière diffuse
        couleur = new float[]{(float) matériau.obtenirRougeDiffue() / 255,
                              (float) matériau.obtenirVertDiffue() / 255,
                              (float) matériau.obtenirBleuDiffue() / 255,
                              1 - transparence};
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, FloatBuffer.wrap(couleur));

        // Réaction à la lumière ambiante
        couleur = new float[]{(float) matériau.obtenirRougeAmbiant() / 255,
                              (float) matériau.obtenirVertAmbiant() / 255,
                              (float) matériau.obtenirBleuAmbiant() / 255,
                              1 - transparence};
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, FloatBuffer.wrap(couleur));

        // Réaction à la lumière spéculaire
        couleur = new float[]{(float) matériau.obtenirRougeSpéculaire() / 255,
                              (float) matériau.obtenirVertSpéculaire() / 255,
                              (float) matériau.obtenirBleuSpéculaire() / 255,
                              1 - transparence};
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, FloatBuffer.wrap(couleur));

        // Lumière émissive
        couleur = new float[]{(float) matériau.obtenirRougeEmissif() / 255,
                              (float) matériau.obtenirVertEmissif() / 255,
                              (float) matériau.obtenirBleuEmissif() / 255,
                              1 - transparence};
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, FloatBuffer.wrap(couleur));

        // Réglage de l'atténuation
        gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, 50f);

        // S'il y a une image
        if (matériau.obtenirImage() != null) {

            // Génration d'un numéro de texture
            final int[] tmp = new int[1];
            gl.glGenTextures(1, tmp, 0);
            textureID = tmp[0];

            // Récupère l'image
            IImage image = matériau.obtenirImage();

            // Transparence
            for (int x = 0; x <= image.obtenirLargeur() - 1; x = x + 1)
                for (int y = 0; y <= image.obtenirHauteur() - 1; y = y + 1)
                    image.définirTransparence(x, y, image.obtenirTransparence(x, y) * transparence);

            // Sélectionne le numéro généré
            gl.glBindTexture(GL.GL_TEXTURE_2D, textureID);

            // Charge la texture
            TextureData données = TextureIO.newTextureData((BufferedImage) image, GL.GL_RGB8, GL.GL_BGR, true);
            gl.glTexImage2D(GL.GL_TEXTURE_2D,
                            0,
                            données.getInternalFormat(),
                            données.getWidth(),
                            données.getHeight(),
                            données.getBorder(),
                            données.getPixelFormat(),
                            données.getPixelType(),
                            données.getBuffer());

            // Restaure Transparence
            for (int x = 0; x <= image.obtenirLargeur() - 1; x = x + 1)
                for (int y = 0; y <= image.obtenirHauteur() - 1; y = y + 1)
                    image.définirTransparence(x, y, image.obtenirTransparence(x, y) / transparence);

            // Filtrage de la texture
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR);
            gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR);

            // Utiliser l'alpha pour la transparence
            gl.glTexEnvf(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_DECAL);

            // Les textures doivent être répétées
            gl.glTexParameterf(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL.GL_REPEAT);

        }

        // Mémorise le matériau comme matériau courant
        materiauCourant = matériau;

    }// FIN mettreEnPlaceTexture


    /** Actualise la caméra */
    private void actualiserCaméra() {

        // Mode caméra
        gl.glMatrixMode(GL.GL_PROJECTION);

        // Initialisation
        gl.glLoadIdentity();

        // Initialise la perspective
        gl.glFrustum(-1.0, 1.0, -1.0, 1.0, 1.5, 20.0);

        // Rotation
        gl.glRotated(caméra.getAngleX(), 1, 0, 0);
        gl.glRotated(caméra.getAngleY(), 0, 1, 0);
        gl.glRotated(caméra.getAngleZ(), 0, 0, 1);

        // Position
        gl.glTranslated(caméra.getX(), caméra.getY(), caméra.getZ());

        // Mode objet/lumières
        gl.glMatrixMode(GL.GL_MODELVIEW);

    }// FIN actualiserCaméra


    /** Retourne le composant graphique java.awt.Component dans lequel s'effectue l'affichage. Null si l'affichage est géré nativement dans une fenêtre indépendante */
    public Component getComponent() {

        return canevas;

    }// FIN retComponent


    /** Rafraichissment de l'affichage */
    public void display(GLAutoDrawable arg0) {

        // Attend si on doit changer l'univers
        try {
            synchronized (this) {

                // Si on a demander de changer l'univers
                if (drapeauUnivers) {

                    // Signal que c'est OK, on peut le changer
                    drapeauUnivers = false;
                    notifyAll();

                    // Attend que le changement soit fait
                    while (!drapeauUnivers)
                        wait();

                    // Mémorise qu'il a été changé
                    drapeauUnivers = false;

                }

            }
        } catch (InterruptedException e) {
        }

        // Attend l'autorisation de rafraichir
        try {
            synchronized (this) {
                while (!drapeauActualiser)
                    wait();
            }
        } catch (InterruptedException e) {
        }

        // Sauvegarde
        gl.glPushMatrix();

        // Nettoie
        gl.glClear(GL.GL_COLOR_BUFFER_BIT);

        // Actualise la caméra
        actualiserCaméra();

        // Actualise les lumières
        actualiserLumières();

        // Actualise les objets 3D
        actualiserObjets3D();

        // Valide
        gl.glFlush();

        // Restaure
        gl.glPopMatrix();

        // Fin de l'actualisation
        synchronized (this) {
            drapeauActualiser = false;
            notifyAll();
        }

    }// FIN display


    /** Non implémenté dans JOGL */
    public void displayChanged(GLAutoDrawable arg0,
                               boolean arg1,
                               boolean arg2) {
    }


    /** Initialisation de OpenGL */
    public void init(GLAutoDrawable arg0) {

        setRésolution(800, 600);
        //gl.glEnable(GL.GL_DEPTH_TEST);
        gl.glEnable(GL.GL_LIGHTING);
        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_LIGHT1);
        gl.glEnable(GL.GL_LIGHT2);// TODO Autres lumières
        gl.glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glEnable(GL.GL_TEXTURE_2D);

        gl.glDisable(GL.GL_COLOR_MATERIAL);
        //gl.glColorMaterial(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE);
        float mcolor[] = {1.0f, 1.0f, 1.0f, 1.0f};
        gl.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, mcolor, 0);

    }// FIN init


    /** La fenêtre a été redimensionné */
    public void reshape(GLAutoDrawable gLDrawable,
                        int x,
                        int y,
                        int width,
                        int height) {

        // Si c'est le bon affichage
        if (gLDrawable.getGL() == gl) {

            // Evite la division par zéro
            if (height <= 0)
                height = 1;

            // Reconfigure la résolution
            setRésolution(width, height);

            // Initialise le positionnement d'openGL
            gl.glMatrixMode(GL.GL_PROJECTION);
            gl.glLoadIdentity();
            glu.gluPerspective(45.0f, width / height, 1.0, 20.0);
            gl.glMatrixMode(GL.GL_MODELVIEW);
            gl.glLoadIdentity();

        }

    }// FIN reshape


}// FIN Classe
